package Envelopes;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Random;
import java.util.TimeZone;

import com.dukascopy.api.Configurable;
import com.dukascopy.api.Filter;
import com.dukascopy.api.IAccount;
import com.dukascopy.api.IBar;
import com.dukascopy.api.IConsole;
import com.dukascopy.api.IContext;
import com.dukascopy.api.IEngine;
import com.dukascopy.api.IHistory;
import com.dukascopy.api.IIndicators;
import com.dukascopy.api.IMessage;
import com.dukascopy.api.IOrder;
import com.dukascopy.api.IStrategy;
import com.dukascopy.api.ITick;
import com.dukascopy.api.Instrument;
import com.dukascopy.api.JFException;
import com.dukascopy.api.OfferSide;
import com.dukascopy.api.Period;
import com.dukascopy.api.IEngine.OrderCommand;
import com.dukascopy.api.IIndicators.AppliedPrice;
import com.dukascopy.api.IOrder.State;

public class Envelopes_v01 implements IStrategy{
	
	@Configurable("Open hour") public int _OpenHour = 4;
	@Configurable("Close hour") public int _CloseHour = 5;
	
	@Configurable("Envelope period") public int _EnvelopePeriod = 21;
	@Configurable("Envelope deviation") public double _EnvelopeDeviation = 0.03;
	@Configurable("Amount of space bars") public int _SpaceBars = 10;
	
	@Configurable("Order lots") public double _OrdLots = 0.1;
	@Configurable("Instrument") public Instrument _GlobalInstrument = Instrument.EURUSD;
	@Configurable("ADX Level") public int _ADXLevel = 30;
	@Configurable("Envelope delta in pips") public int _EnvDelta = 2;
	
	private Period _GlobalPeriod = Period.ONE_MIN;
	
	private IEngine engine;
	private IConsole console;
	private IHistory history;
	private IContext context;
	private IOrder order = null;
	private SimpleDateFormat sdf;
	private IIndicators indicators = null;
	
	private double lastTickBid = 0;
	private double lastTickAsk = 0;
	
	private double[] _EnvelopeAsk = null;
	private double[] _EnvelopeBid = null;
	private double[][] _Envelopes1 = null;
	private double _ADX = 0;
	
	private int _Count = 0;
	
	private boolean _Trade = false;
	
	@Override
	public void onStart(IContext context) throws JFException {
		// TODO Auto-generated method stub
		this.engine = context.getEngine();
		this.console = context.getConsole();
		this.history = context.getHistory();
		this.context = context;
		this.indicators = context.getIndicators();
		
		sdf = new SimpleDateFormat();
    	DateFormat.getDateInstance(DateFormat.LONG);
    	sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
    	
    	_CloseHour = _OpenHour + 2;
	}

	@Override
	public void onTick(Instrument instrument, ITick tick) throws JFException {
		// TODO Auto-generated method stub
		
		if(!instrument.equals(_GlobalInstrument) || (_EnvelopeBid == null)){
    		return;
    	}
		
		if(CheckDate(tick.getTime())){
			return;
		}
		
		
		Calendar calendar = Calendar.getInstance();
    	calendar .setTimeZone(TimeZone.getTimeZone("GMT"));
    	calendar .setTimeInMillis(tick.getTime());
    	
    	int currentDay = calendar.get(Calendar.DAY_OF_WEEK);
    	int currentHour = calendar.get(Calendar.HOUR_OF_DAY);
    	
    	if(engine.getOrders().size() != 0){
    		for (IOrder order : engine.getOrders()){
    			if(order.getState() == State.FILLED){
    				if(order.getOrderCommand() == OrderCommand.BUY){
    					if(tick.getBid() > _EnvelopeBid[1]){
    						order.close();
    					}
    				}
    				else if(order.getOrderCommand() == OrderCommand.SELL){
    					if(tick.getAsk() < _EnvelopeAsk[0]){
    						order.close();
    					}
    				}
    			}
    		}
    	}
    	
    	if((currentHour >= _OpenHour) && (currentHour <= _CloseHour)){
    		_Trade = true;
    	}
    	
    	if((currentHour > _CloseHour) || (currentHour < _OpenHour)){
    		_Trade = false;
    	}
    	
    	if((_Trade) && (_ADX < _ADXLevel)){
    		//BUY
			if((lastTickAsk <= _EnvelopeAsk[0]) && (tick.getAsk() > _EnvelopeAsk[0]) && (_Count == 0)){
				order = engine.submitOrder(getLabel(instrument,"MAIN",_OrdLots), instrument, OrderCommand.BUY, _OrdLots,tick.getAsk(),5,0,0);
				_Count = _SpaceBars;
			}
			
			//SELL
			if((lastTickBid >= _EnvelopeBid[1]) && (tick.getBid() < _EnvelopeBid[1]) && (_Count == 0)){
				order = engine.submitOrder(getLabel(instrument,"MAIN",_OrdLots), instrument, OrderCommand.SELL, _OrdLots,tick.getBid(),5,0,0);
				_Count = _SpaceBars;
			}
    	}
		lastTickBid = tick.getBid();
		lastTickAsk = tick.getAsk();
	}

	@Override
	public void onBar(Instrument instrument, Period period, IBar askBar,
			IBar bidBar) throws JFException {
		// TODO Auto-generated method stub
		
		if(!instrument.equals(_GlobalInstrument) || !period.equals(_GlobalPeriod)) {
    		return;
    	}
		
		if(_Count > 0)
			_Count--;
		
		_EnvelopeBid = indicators.emaEnvelope(_GlobalInstrument, _GlobalPeriod, OfferSide.BID, AppliedPrice.CLOSE, _EnvelopePeriod, _EnvelopeDeviation, 1);
		_EnvelopeAsk = indicators.emaEnvelope(_GlobalInstrument, _GlobalPeriod, OfferSide.ASK, AppliedPrice.CLOSE, _EnvelopePeriod, _EnvelopeDeviation, 1);
		//_Envelopes1 = indicators.emaEnvelope(_GlobalInstrument, _GlobalPeriod, OfferSide.BID, AppliedPrice.CLOSE, 
		//		_EnvelopePeriod, _EnvelopeDeviation, Filter.NO_FILTER, 1, bidBar.getTime(), 3);
		_ADX = indicators.adx(_GlobalInstrument, _GlobalPeriod, OfferSide.BID, _EnvelopePeriod, 1);
		console.getOut().println("Up bid envelope" + _EnvelopeBid[1]);
		console.getOut().println("Down bid envelope" + _EnvelopeBid[0]);
		console.getOut().println("Up ask envelope" + _EnvelopeAsk[1]);
		console.getOut().println("Down ask envelope" + _EnvelopeAsk[0]);
	}

	@Override
	public void onMessage(IMessage message) throws JFException {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void onAccount(IAccount account) throws JFException {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void onStop() throws JFException {
		// TODO Auto-generated method stub
		
	}
	
	 protected Boolean CheckDate(long time){
	    
		Calendar calendar = Calendar.getInstance();
    	calendar .setTimeZone(TimeZone.getTimeZone("GMT"));
    	calendar .setTimeInMillis(time);
    	
    	int currentHour = calendar.get(Calendar.HOUR_OF_DAY);
    	int currentDay = calendar.get(Calendar.DAY_OF_WEEK);
    	
    	if((currentDay == Calendar.FRIDAY) || (currentDay == Calendar.SATURDAY)|| (currentDay == Calendar.SUNDAY)){
    		return true;
    	}
    	return false;
    }
    
    protected String getLabel(Instrument instrument, String com,double lot) {
    	
        String label = instrument.name();
       
        Random generator = new Random();
        int r = generator.nextInt(99999);

        label = label.substring(0, 2) + label.substring(3, 5);
        
        label = label + r + com;
        label = label.toLowerCase();
        return label;
    }
}
